﻿using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Intrinsics;
using System.Runtime.CompilerServices;
using System.Buffers.Binary;

namespace Ulid;

/// <summary>
/// 表示一个 <see cref="Ulid"/> 通用唯一字典序可排序标识符（Universally Unique Lexicographically Sortable Identifier）
/// 基于/受启发于 <see href="https://github.com/alizain/ulid">alizain/ulid</see>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[TypeConverter(typeof(UlidTypeConverter))]
[Serializable]
[ComVisible(true)]
[DebuggerDisplay("{ToString(),nq}")]
public struct Ulid : IEquatable<Ulid>, IComparable<Ulid>, IComparable, ISerializable, IFormattable
{
    private const char _hyphen_char = '-';
    private static readonly string _hyphen_string = _hyphen_char.ToString();

    private const string _invalidbase32stringmessage = "Invalid Base32 string";
    private const string _invalidlengthmessage = "Invalid length";

    // Base32 "alphabet"
    private const string _base32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
    // 用于大幅提升速度的字符到索引的查找数组，因为能够以时间复杂度 O (1) 找到一个字符的索引。使用 255 作为无效索引的 “哨兵” 值
    // 这使用了 Roslyn 优化来引用程序集的静态数据段，并且不会产生任何内存分配
    private static ReadOnlySpan<byte> _c2b32 => [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, 0, 22, 23, 24, 25, 26, 255, 27, 28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, 0, 22, 23, 24, 25, 26, 255, 27, 28, 29, 30, 31];
    internal const long _unixepochmilliseconds = 62135596800000;

    // ULID的内部组成部分
    private readonly byte _a; private readonly byte _b; private readonly byte _c; private readonly byte _d;
    private readonly byte _e; private readonly byte _f; private readonly byte _g; private readonly byte _h;
    private readonly byte _i; private readonly byte _j; private readonly byte _k; private readonly byte _l;
    private readonly byte _m; private readonly byte _n; private readonly byte _o; private readonly byte _p;

    // 用于 ULID 的默认 EPOCH
    internal static readonly DateTimeOffset _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    /// <summary>
    /// 表示 <see cref="Ulid"/> 可能的最小值。此字段为只读
    /// </summary>
    public static readonly Ulid MinValue = new(_epoch, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

    /// <summary>
    /// 表示 <see cref="Ulid"/> 可能的最大值。此字段为只读
    /// </summary>
    public static readonly Ulid MaxValue = new(DateTimeOffset.MaxValue, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);

    /// <summary>
    /// <see cref="Ulid"/> 结构的一个只读实例，其值全为零
    /// </summary>
    public static readonly Ulid Empty = MinValue;

    /// <summary>
    /// 获取 <see cref="Ulid"/> 的 “时间部分”
    /// </summary>
    public readonly DateTimeOffset Time
        => ByteArrayToDateTimeOffset([_a, _b, _c, _d, _e, _f]);

    /// <summary>
    /// 获取 <see cref="Ulid"/> 的 “随机部分”
    /// </summary>
    public readonly byte[] Random
        => [_g, _h, _i, _j, _k, _l, _m, _n, _o, _p];

    /// <summary>
    /// 基于当前 UTC 时间和默认的 <see cref="CSUlidRng"/> 随机数生成器，创建并返回一个新的 <see cref="Ulid"/>
    /// </summary>
    /// <returns>返回一个新的 <see cref="Ulid"/>.</returns>
    public static Ulid NewUlid()
        => NewUlid(DateTimeOffset.UtcNow, BaseUlidRng.DEFAULTRNG);

    /// <summary>
    /// 基于指定时间和默认的 <see cref="CSUlidRng"/> 随机数生成器，创建并返回一个新的 <see cref="Ulid"/>
    /// </summary>
    /// <param name="time">
    /// 用于 <see cref="Ulid"/> 的时间部分的 <see cref="DateTimeOffset"/>
    /// </param>
    /// <returns>返回一个新的 <see cref="Ulid"/>.</returns>
    public static Ulid NewUlid(DateTimeOffset time)
        => NewUlid(time, BaseUlidRng.DEFAULTRNG);

    /// <summary>
    /// 基于当前 UTC 时间和指定随机数生成器，创建并返回一个新的 <see cref="Ulid"/>
    /// </summary>
    /// <param name="rng">用于生成随机数的 <see cref="IUlidRng"/></param>
    /// <returns>返回一个新的 <see cref="Ulid"/>.</returns>
    public static Ulid NewUlid(IUlidRng rng)
        => NewUlid(DateTimeOffset.UtcNow, rng);

    /// <summary>
    /// 基于指定时间和指定随机数生成器，创建并返回一个新的 <see cref="Ulid"/>
    /// </summary>
    /// <param name="time">
    /// 用于 <see cref="Ulid"/> 的时间部分的 <see cref="DateTimeOffset"/>
    /// </param>
    /// <param name="rng">用于生成随机数的 <see cref="IUlidRng"/></param>
    /// <returns>返回一个新的 <see cref="Ulid"/>.</returns>
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="rng"/> is <see langword="null"/>.</exception>
    public static Ulid NewUlid(DateTimeOffset time, IUlidRng rng)
    {
        if (rng == null)
        {
            throw new ArgumentNullException(nameof(rng));
        }
        else
        {
            Span<byte> buffer = stackalloc byte[BaseUlidRng.RANDLEN];
            rng.GetRandomBytes(buffer, time);
            return new Ulid(time, buffer);
        }
    }

    /// <summary>
    /// 通过使用指定的字节数组来初始化 <see cref="Ulid"/> 结构的新实例
    /// </summary>
    /// <param name="bytes">
    /// 一个包含用于初始化 <see cref="Ulid"/> 值的 16 位元素字节数组
    /// </param>
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="bytes"/> is <see langword="null"/>.</exception>
    /// <exception cref="ArgumentException">Thrown when <paramref name="bytes"/>  is anything but 16 bytes long.</exception>
    public Ulid(byte[] bytes) : this(bytes.AsSpan()) { }

    /// <summary>
    /// 通过使用指定的 Span 字节来初始化 <see cref="Ulid"/> 结构的一个新实例
    /// </summary>
    /// <param name="bytes">
    /// 一个包含用于初始化 <see cref="Ulid"/> 值的 16 位 span 字节数组
    /// </param>
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="bytes"/> is <see langword="null"/>.</exception>
    /// <exception cref="ArgumentException">Thrown when <paramref name="bytes"/>  is anything but 16 bytes long.</exception>
    public Ulid(ReadOnlySpan<byte> bytes)
    {
        if (bytes.Length != 16)
        {
            throw new ArgumentException("16 bytes are required", nameof(bytes));
        }

        ref byte src = ref MemoryMarshal.GetReference(bytes);
        Unsafe.As<Ulid, Vector128<byte>>(ref this) = Unsafe.ReadUnaligned<Vector128<byte>>(ref src);
    }

    /// <summary>
    /// 通过使用指定的 <see cref="Guid"/> 来初始化 <see cref="Ulid"/> 结构的一个新实例
    /// </summary>
    /// <param name="guid">一个表示 <see cref="Ulid"/> 的 <see cref="Guid"/></param>
    public Ulid(Guid guid)
    {
        Span<byte> buffer = stackalloc byte[16];
        guid.TryWriteBytes(buffer);
        this = new Ulid(buffer);
    }

    /// <summary>
    /// 通过使用指定字符串所表示的值来初始化 <see cref="Ulid"/> 结构的一个新实例
    /// </summary>
    /// <param name="ulid">一个包含 <see cref="Ulid"/> 的字符串</param>
    public Ulid(string ulid)
        => this = Parse(ulid);

    /// <summary>
    /// 通过使用指定 Span 所表示的值来初始化 <see cref="Ulid"/> 结构的一个新实例
    /// </summary>
    /// <param name="ulid"></param>
    public Ulid(ReadOnlySpan<char> ulid)
        => this = Parse(ulid);

    // 内部构造函数
    private Ulid(DateTimeOffset timePart, ReadOnlySpan<byte> randomPart)
    {
        ArgumentOutOfRangeException.ThrowIfLessThan(timePart, _epoch);

        if (randomPart.Length != 10)
        {
            throw new InvalidOperationException($"{nameof(randomPart)} must be 10 bytes");
        }

        long millis = ToUnixTimeMilliseconds(timePart);
        millis = BinaryPrimitives.ReverseEndianness(millis);
        millis >>= 16;      // drop byte 6 & 7
        Unsafe.As<Ulid, long>(ref this) = millis;

        ref byte src = ref MemoryMarshal.GetReference(randomPart);
        ref byte thisRef = ref Unsafe.As<Ulid, byte>(ref this);
        thisRef = ref Unsafe.Add(ref thisRef, 6);
        Unsafe.CopyBlockUnaligned(ref thisRef, ref src, 10);
    }

    #region 辅助方法
    private static DateTimeOffset FromUnixTimeMilliseconds(long milliseconds)
    {
        var ticks = (milliseconds * TimeSpan.TicksPerMillisecond) + (_unixepochmilliseconds * 10000);
        return new DateTimeOffset(ticks, TimeSpan.Zero);
    }

    internal static long ToUnixTimeMilliseconds(DateTimeOffset value)
    {
        var milliseconds = value.Ticks / TimeSpan.TicksPerMillisecond;
        return milliseconds - _unixepochmilliseconds;
    }

    private static DateTimeOffset ByteArrayToDateTimeOffset(byte[] value)
    {
        var tmp = new byte[] { value[5], value[4], value[3], value[2], value[1], value[0], 0, 0 };  // Pad with 2 "lost" bytes
        return FromUnixTimeMilliseconds(BitConverter.ToInt64(tmp, 0));
    }

    private static string ToBase32(byte[] value)
        =>
        // 经过手动优化的展开循环
        value.Length switch
        {
            // 时间部分
            6 => new string(
                    [
                    /* 0  */ _base32[(value[0] & 224) >> 5],                             /* 1  */ _base32[value[0] & 31],
                    /* 2  */ _base32[(value[1] & 248) >> 3],                             /* 3  */ _base32[((value[1] & 7) << 2) | ((value[2] & 192) >> 6)],
                    /* 4  */ _base32[(value[2] & 62) >> 1],                              /* 5  */ _base32[((value[2] & 1) << 4) | ((value[3] & 240) >> 4)],
                    /* 6  */ _base32[((value[3] & 15) << 1) | ((value[4] & 128) >> 7)],  /* 7  */ _base32[(value[4] & 124) >> 2],
                    /* 8  */ _base32[((value[4] & 3) << 3) | ((value[5] & 224) >> 5)],   /* 9  */ _base32[value[5] & 31],
                    ]
                ),
            // 随机部分
            10 => new string(
                    [
                    /* 0  */ _base32[(value[0] & 248) >> 3],                             /* 1  */ _base32[((value[0] & 7) << 2) | ((value[1] & 192) >> 6)],
                    /* 2  */ _base32[(value[1] & 62) >> 1],                              /* 3  */ _base32[((value[1] & 1) << 4) | ((value[2] & 240) >> 4)],
                    /* 4  */ _base32[((value[2] & 15) << 1) | ((value[3] & 128) >> 7)],  /* 5  */ _base32[(value[3] & 124) >> 2],
                    /* 6  */ _base32[((value[3] & 3) << 3) | ((value[4] & 224) >> 5)],   /* 7  */ _base32[value[4] & 31],
                    /* 8  */ _base32[(value[5] & 248) >> 3],                             /* 9  */ _base32[((value[5] & 7) << 2) | ((value[6] & 192) >> 6)],
                    /* 10 */ _base32[(value[6] & 62) >> 1],                              /* 11 */ _base32[((value[6] & 1) << 4) | ((value[7] & 240) >> 4)],
                    /* 12 */ _base32[((value[7] & 15) << 1) | ((value[8] & 128) >> 7)],  /* 13 */ _base32[(value[8] & 124) >> 2],
                    /* 14 */ _base32[((value[8] & 3) << 3) | ((value[9] & 224) >> 5)],   /* 15 */ _base32[value[9] & 31],
                    ]
                ),
            _ => throw new InvalidOperationException(_invalidlengthmessage),
        };

    private static void ToBase32(ReadOnlySpan<byte> value, Span<char> buffer)
    {
        // 时间部分
        if (value.Length == 6 && buffer.Length > 10)
        {
            buffer[0] = _base32[(value[0] & 224) >> 5]; buffer[1] = _base32[value[0] & 31];
            buffer[2] = _base32[(value[1] & 248) >> 3]; buffer[3] = _base32[((value[1] & 7) << 2) | ((value[2] & 192) >> 6)];
            buffer[4] = _base32[(value[2] & 62) >> 1]; buffer[5] = _base32[((value[2] & 1) << 4) | ((value[3] & 240) >> 4)];
            buffer[6] = _base32[((value[3] & 15) << 1) | ((value[4] & 128) >> 7)]; buffer[7] = _base32[(value[4] & 124) >> 2];
            buffer[8] = _base32[((value[4] & 3) << 3) | ((value[5] & 224) >> 5)]; buffer[9] = _base32[value[5] & 31];
        }
        // 随机部分
        else if (value.Length == 10 && buffer.Length >= 16)
        {
            buffer[0] = _base32[(value[0] & 248) >> 3]; buffer[1] = _base32[((value[0] & 7) << 2) | ((value[1] & 192) >> 6)];
            buffer[2] = _base32[(value[1] & 62) >> 1]; buffer[3] = _base32[((value[1] & 1) << 4) | ((value[2] & 240) >> 4)];
            buffer[4] = _base32[((value[2] & 15) << 1) | ((value[3] & 128) >> 7)]; buffer[5] = _base32[(value[3] & 124) >> 2];
            buffer[6] = _base32[((value[3] & 3) << 3) | ((value[4] & 224) >> 5)]; buffer[7] = _base32[value[4] & 31];
            buffer[8] = _base32[(value[5] & 248) >> 3]; buffer[9] = _base32[((value[5] & 7) << 2) | ((value[6] & 192) >> 6)];
            buffer[10] = _base32[(value[6] & 62) >> 1]; buffer[11] = _base32[((value[6] & 1) << 4) | ((value[7] & 240) >> 4)];
            buffer[12] = _base32[((value[7] & 15) << 1) | ((value[8] & 128) >> 7)]; buffer[13] = _base32[(value[8] & 124) >> 2];
            buffer[14] = _base32[((value[8] & 3) << 3) | ((value[9] & 224) >> 5)]; buffer[15] = _base32[value[9] & 31];
        }
    }

    private static byte[] FromBase32(string v)
    {
        // 经过手动优化的展开循环
        unchecked
        {
            switch (v.Length)
            {
                case 10:    // 时间部分
                    return
                    [
                    /* 0 */ (byte)((_c2b32[v[0]] << 5) | _c2b32[v[1]]),                                   /* 1 */ (byte)((_c2b32[v[2]] << 3) | (_c2b32[v[3]] >> 2)),
                    /* 2 */ (byte)((_c2b32[v[3]] << 6) | (_c2b32[v[4]] << 1) | (_c2b32[v[5]] >> 4)),       /* 3 */ (byte)((_c2b32[v[5]] << 4) | (_c2b32[v[6]] >> 1)),
                    /* 4 */ (byte)((_c2b32[v[6]] << 7) | (_c2b32[v[7]] << 2) | (_c2b32[v[8]] >> 3)),       /* 5 */ (byte)((_c2b32[v[8]] << 5) | _c2b32[v[9]]),
                    ];
                case 16:    // 随机部分
                    return
                    [
                    /* 0 */ (byte)((_c2b32[v[0]] << 3) | (_c2b32[v[1]] >> 2)),                            /* 1 */ (byte)((_c2b32[v[1]] << 6) | (_c2b32[v[2]] << 1) | (_c2b32[v[3]] >> 4)),
                    /* 2 */ (byte)((_c2b32[v[3]] << 4) | (_c2b32[v[4]] >> 1)),                            /* 3 */ (byte)((_c2b32[v[4]] << 7) | (_c2b32[v[5]] << 2) | (_c2b32[v[6]] >> 3)),
                    /* 4 */ (byte)((_c2b32[v[6]] << 5) | _c2b32[v[7]]),                                   /* 5 */ (byte)((_c2b32[v[8]] << 3) | (_c2b32[v[9]] >> 2)),
                    /* 6 */ (byte)((_c2b32[v[9]] << 6) | (_c2b32[v[10]] << 1) | (_c2b32[v[11]] >> 4)),     /* 7 */ (byte)((_c2b32[v[11]] << 4) | (_c2b32[v[12]] >> 1)),
                    /* 8 */ (byte)((_c2b32[v[12]] << 7) | (_c2b32[v[13]] << 2) | (_c2b32[v[14]] >> 3)),    /* 9 */ (byte)((_c2b32[v[14]] << 5) | _c2b32[v[15]]),
                    ];
            }
        }
        throw new InvalidOperationException(_invalidlengthmessage);
    }

    private static byte[] FromBase32(ReadOnlySpan<char> v)
    {
        // 经过手动优化的展开循环
        unchecked
        {
            switch (v.Length)
            {
                case 10:    // 时间部分
                    return
                    [
                    /* 0 */ (byte)((_c2b32[v[0]] << 5) | _c2b32[v[1]]),                                   /* 1 */ (byte)((_c2b32[v[2]] << 3) | (_c2b32[v[3]] >> 2)),
                    /* 2 */ (byte)((_c2b32[v[3]] << 6) | (_c2b32[v[4]] << 1) | (_c2b32[v[5]] >> 4)),       /* 3 */ (byte)((_c2b32[v[5]] << 4) | (_c2b32[v[6]] >> 1)),
                    /* 4 */ (byte)((_c2b32[v[6]] << 7) | (_c2b32[v[7]] << 2) | (_c2b32[v[8]] >> 3)),       /* 5 */ (byte)((_c2b32[v[8]] << 5) | _c2b32[v[9]]),
                    ];
                case 16:    // 随机部分
                    return
                    [
                    /* 0 */ (byte)((_c2b32[v[0]] << 3) | (_c2b32[v[1]] >> 2)),                            /* 1 */ (byte)((_c2b32[v[1]] << 6) | (_c2b32[v[2]] << 1) | (_c2b32[v[3]] >> 4)),
                    /* 2 */ (byte)((_c2b32[v[3]] << 4) | (_c2b32[v[4]] >> 1)),                            /* 3 */ (byte)((_c2b32[v[4]] << 7) | (_c2b32[v[5]] << 2) | (_c2b32[v[6]] >> 3)),
                    /* 4 */ (byte)((_c2b32[v[6]] << 5) | _c2b32[v[7]]),                                   /* 5 */ (byte)((_c2b32[v[8]] << 3) | (_c2b32[v[9]] >> 2)),
                    /* 6 */ (byte)((_c2b32[v[9]] << 6) | (_c2b32[v[10]] << 1) | (_c2b32[v[11]] >> 4)),     /* 7 */ (byte)((_c2b32[v[11]] << 4) | (_c2b32[v[12]] >> 1)),
                    /* 8 */ (byte)((_c2b32[v[12]] << 7) | (_c2b32[v[13]] << 2) | (_c2b32[v[14]] >> 3)),    /* 9 */ (byte)((_c2b32[v[14]] << 5) | _c2b32[v[15]]),
                    ];
            }
        }
        throw new InvalidOperationException(_invalidlengthmessage);
    }
    #endregion

    /// <summary>
    /// 将表示 <see cref="Ulid"/> 的字符串转换为等效的 <see cref="Ulid"/>
    /// </summary>
    /// <param name="s">需要转换的字符串</param>
    /// <returns>与字符串等效的 <see cref="Ulid"/> 值</returns>
    /// <exception cref="ArgumentNullException"><paramref name="s"/> is null or empty.</exception>
    /// <exception cref="FormatException"><paramref name="s"/> is not in the correct format.</exception>
    public static Ulid Parse(string? s)
        => string.IsNullOrEmpty(s) ? throw new ArgumentNullException(nameof(s)) : Parse(s.AsSpan());


    /// <summary>
    /// 将表示 <see cref="Ulid"/> 的 Span 转换为等效的 <see cref="Ulid"/>
    /// </summary>
    /// <param name="span">需要转换的 <see cref="ReadOnlySpan{T}"/></param>
    /// <returns>与 Span 等效的 <see cref="Ulid"/></returns>
    /// <exception cref="ArgumentNullException"><paramref name="span"/> is null or empty.</exception>
    /// <exception cref="FormatException"><paramref name="span"/> is not in the correct format.</exception>
    /// <remarks>Hyphens not allowed</remarks>
    public static Ulid Parse(ReadOnlySpan<char> span)
    {
        if (span.IsEmpty)
        {
            throw new ArgumentNullException(nameof(span));
        }

        if (span.Length > 26)
        {
            Span<char> buffer = stackalloc char[26];

            var position = 0;
            for (var i = 0; i < span.Length; i++)
            {
                int value = span[i];
                if (value != _hyphen_char)
                {
                    if ((uint)value >= (uint)_c2b32.Length || _c2b32[value] > 31)
                    {
                        throw new FormatException(_invalidlengthmessage);
                    }

                    buffer[position++] = (char)value;
                }
            }

            return position != 26
                ? throw new FormatException(_invalidlengthmessage)
                : new Ulid(ByteArrayToDateTimeOffset(FromBase32(buffer[..10])), FromBase32(buffer[10..26]));
        }

        if (span.Length != 26)
        {
            throw new FormatException(_invalidlengthmessage);
        }

        // 通过对每个字符进行查找，并查看其对应的索引是否小于 32，以此来检查所有字符是否都在允许范围内
        for (var i = 0; i < span.Length; i++)
        {
            int val = span[i];
            if ((uint)val >= (uint)_c2b32.Length || _c2b32[val] > 31)
            {
                throw new FormatException(_invalidlengthmessage);
            }
        }

        return new Ulid(ByteArrayToDateTimeOffset(FromBase32(span[..10])), FromBase32(span[10..26]));
    }

    /// <summary>
    /// 将 <see cref="Ulid"/> 的字符串表示形式转换为 <see cref="Ulid"/> 的实例
    /// 返回值指示转换是否成功
    /// </summary>
    /// <param name="s">需要转换的字符串</param>
    /// <param name="result">如果转换失败，则包含 <see cref="Empty"/>
    /// </param>
    /// <returns>如果成功转换，则为 true；否则为 false</returns>
    public static bool TryParse(string? s, out Ulid result)
    {
        try
        {
            result = Parse(s);
            return true;
        }
        catch
        {
            result = Empty;
            return false;
        }
    }

    /// <summary>
    /// 将 <see cref="Ulid"/> 的 Span 表示形式转换为 <see cref="Ulid"/> 的实例
    /// 返回值指示转换是否成功
    /// </summary>
    /// <param name="span">需要转换的 <see cref="ReadOnlySpan{T}"/></param>
    /// <param name="result">如果转换失败，则包含 <see cref="Empty"/>
    /// </param>
    /// <returns>如果成功转换，则为 true；否则为 false</returns>
    public static bool TryParse(ReadOnlySpan<char> s, out Ulid result)
    {
        try
        {
            result = Parse(s);
            return true;
        }
        catch
        {
            result = Empty;
            return false;
        }
    }

    /// <summary>
    /// 返回 <see cref="Ulid"/> 的字符串表示形式
    /// </summary>
    /// <returns><see cref="Ulid"/> 的字符串表示形式</returns>
    public override readonly string ToString() =>
        string.Create(26, this, static (buffer, state) =>
        {
            ref byte thisRef = ref Unsafe.As<Ulid, byte>(ref state);
            ReadOnlySpan<byte> span = MemoryMarshal.CreateReadOnlySpan(ref thisRef, 16);

            ToBase32(span[..6], buffer);
            ToBase32(span[6..], buffer[10..]);
        });


    /// <summary>
    /// 返回一个包含此实例值的 16 元素字节数组
    /// </summary>
    /// <returns>一个 16 元素的字节数组</returns>
    public readonly byte[] ToByteArray()
        => [_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p];

    /// <summary>
    /// 返回一个表示此实例值的 <see cref="Guid"/>
    /// </summary>
    /// <returns>一个表示此实例值的<see cref="Guid"/></returns>
    public Guid ToGuid()
    {
        ref byte thisRef = ref Unsafe.As<Ulid, byte>(ref this);
        ReadOnlySpan<byte> span = MemoryMarshal.CreateReadOnlySpan(ref thisRef, 16);

        return new Guid(span);
    }

    /// <summary>
    /// 此实例和指定的 <see cref="Ulid"/> 对象是否表示相同的值
    /// </summary>
    public readonly bool Equals(Ulid other)
        => this == other;

    public override readonly bool Equals(object? obj)
        =>
        // Check that obj is a ulid first
        obj != null && obj is Ulid ulid && Equals(ulid);

    /// <summary>
    /// 将此实例与指定的 <see cref="Ulid"/> 对象进行比较
    /// </summary>
    /// <param name="other">一个要与此实例进行比较的 <see cref="Ulid"/></param>
    /// <returns>
    ///     <para>
    ///     一个有符号数，指示此实例与另一个实例的相对值
    ///     </para>
    ///     <list type="table">
    ///         <listheader>
    ///             <term>返回值</term>
    ///             <term>描述</term>
    ///         </listheader>
    ///         <item>
    ///             <term>负整数</term>
    ///             <term>此实例小于另一个实例</term>
    ///         </item>
    ///         <item>
    ///             <term>0</term>
    ///             <term>此实例等于另一个实例</term>
    ///         </item>
    ///         <item>
    ///             <term>正整数</term>
    ///             <term>此实例大于另一个实例</term>
    ///         </item>
    ///     </list>
    /// </returns>
    public readonly int CompareTo(Ulid other)
    {
        var d = other.ToByteArray();

        return _a != d[0]
            ? _a.CompareTo(d[0])
            : _b != d[1]
            ? _b.CompareTo(d[1])
            : _c != d[2]
            ? _c.CompareTo(d[2])
            : _d != d[3]
            ? _d.CompareTo(d[3])
            : _e != d[4]
            ? _e.CompareTo(d[4])
            : _f != d[5]
            ? _f.CompareTo(d[5])
            : _g != d[6]
            ? _g.CompareTo(d[6])
            : _h != d[7]
            ? _h.CompareTo(d[7])
            : _i != d[8]
            ? _i.CompareTo(d[8])
            : _j != d[9]
            ? _j.CompareTo(d[9])
            : _k != d[10]
            ? _k.CompareTo(d[10])
            : _l != d[11]
            ? _l.CompareTo(d[11])
            : _m != d[12]
            ? _m.CompareTo(d[12])
            : _n != d[13] ? _n.CompareTo(d[13]) : _o != d[14] ? _o.CompareTo(d[14]) : _p != d[15] ? _p.CompareTo(d[15]) : 0;
    }

    /// <summary>
    /// 将此实例与指定的对象进行比较
    /// </summary>
    /// <param name="obj">要比较的对象，可能为空</param>
    /// <returns>
    ///     <para>
    ///     一个有符号数，指示此实例与另一个实例的相对值
    ///     </para>
    ///     <list type="table">
    ///         <listheader>
    ///             <term>返回值</term>
    ///             <term>描述</term>
    ///         </listheader>
    ///         <item>
    ///             <term>负整数</term>
    ///             <term>此实例小于另一个实例</term>
    ///         </item>
    ///         <item>
    ///             <term>0</term>
    ///             <term>此实例等于另一个实例</term>
    ///         </item>
    ///         <item>
    ///             <term>正整数</term>
    ///             <term>此实例大于另一个实例</term>
    ///         </item>
    ///     </list>
    /// </returns>
    public readonly int CompareTo(object? obj)
        => obj == null ? 1 : obj is not Ulid ? throw new ArgumentException("Object must be Ulid", nameof(obj)) : CompareTo((Ulid)obj);

    /// <summary>
    /// 指示两个指定的 <see cref="Ulid"/> 对象的值是否相等
    /// </summary>
    /// <param name="x">要比较的第一个对象</param>
    /// <param name="y">要比较的第二个对象</param>
    public static bool operator ==(Ulid x, Ulid y)
    {
        Vector128<byte> va = Unsafe.As<Ulid, Vector128<byte>>(ref x);
        Vector128<byte> vb = Unsafe.As<Ulid, Vector128<byte>>(ref y);

        return va.Equals(vb);
    }

    /// <summary>
    /// 指示两个指定的 <see cref="Ulid"/> 对象的值是否不相等
    /// </summary>
    /// <param name="x">要比较的第一个对象</param>
    /// <param name="y">要比较的第二个对象</param>
    public static bool operator !=(Ulid x, Ulid y)
        => !(x == y);

    /// <summary>
    /// 返回此实例的哈希码
    /// </summary>
    /// <returns>此实例的哈希码</returns>
    public override int GetHashCode()
    {
        unchecked // 溢出没问题，直接循环处理
        {
            ref byte thisRef = ref Unsafe.As<Ulid, byte>(ref this);
            ReadOnlySpan<byte> span = MemoryMarshal.CreateReadOnlySpan(ref thisRef, 16);
            HashCode hash = new();
            hash.AddBytes(span);
            return hash.ToHashCode();
        }
    }

    public readonly void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        ArgumentNullException.ThrowIfNull(info);

        info.AddValue("d", ToString(), typeof(string));
    }

    private Ulid(SerializationInfo info, StreamingContext context)
    {
        ArgumentNullException.ThrowIfNull(info);

        var x = (string?)info.GetValue("d", typeof(string));
        var d = Parse(x).ToByteArray();

        _a = d[0]; _b = d[1]; _c = d[2]; _d = d[3]; _e = d[4]; _f = d[5]; _g = d[6]; _h = d[7];
        _i = d[8]; _j = d[9]; _k = d[10]; _l = d[11]; _m = d[12]; _n = d[13]; _o = d[14]; _p = d[15];
    }

    public readonly string ToString(string? format, IFormatProvider? formatProvider)
        => ToString();

    public static bool operator <(Ulid left, Ulid right)
        => left.CompareTo(right) < 0;

    public static bool operator <=(Ulid left, Ulid right)
        => left.CompareTo(right) <= 0;

    public static bool operator >(Ulid left, Ulid right)
        => left.CompareTo(right) > 0;

    public static bool operator >=(Ulid left, Ulid right)
        => left.CompareTo(right) >= 0;
}